package com.hzc.gulimall.order.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;

@Slf4j
@Configuration
public class RabbitConfig {

//     @Autowired
    private RabbitTemplate rabbitTemplate;


    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        initRabbitTemplate();
        return rabbitTemplate;
    }

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定制RabbitTemplate
     * 1、服务收到消息就回调
     * 1)、spring.rabbitmq.publisher-confirms=true
     * 2)、设置确认回调
     * 2、消息正确抵达队列就回调
     * 1)、spring.rabbitmq.publisher-returns=true
     * spring.rabbitmq.template.mandatory=true
     * 2)、设置确认回调returnCallback
     * 3、消费端
     * 1)、默认自动确认，只要消息接收到，客户端会自动确认，服务端就会移除这个消息
     * 问题：如果只有一个消息处理成功，宕机了，发生消息丢失。
     * 手动确认模式，只要没有ack，消息一直是unacked状态。
     * 2)、如何签收
     * channel.basicAck(deliveryTag,false);//签收
     * channel.basicNack(delivertTag,false,true);//拒签
     */
//    @PostConstruct//MyRabbitConfig对象创建完成后，执行这个方法
    public void initRabbitTemplate() {
        /**
         * 		设置确认回调
         *  correlationData: 消息的唯一id
         *  ack： 消息是否成功收到
         * 	cause：失败的原因
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack , cause) -> log.info("\n收到消息: " + correlationData + "\tack: " + ack + "\tcause： " + cause));

        /**
         * 设置消息抵达队列回调：可以很明确的知道那些消息失败了
         *
         * message: 投递失败的消息详细信息
         * replyCode: 回复的状态码
         * replyText: 回复的文本内容
         * exchange: 当时这个发送给那个交换机
         * routerKey: 当时这个消息用那个路由键
         */
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routerKey) -> log.error("Fail Message [" + message + "]" + "\treplyCode: " + replyCode + "\treplyText:" + replyText + "\texchange:" + exchange + "\trouterKey:" + routerKey));
    }
}

